﻿using ActiveDirectoryUtilities.DirectoryServiceAccess;
using System;
using System.Collections.Generic;
using System.DirectoryServices.Protocols;
using System.Reflection;
using System.Text;


namespace TrustCheck
{
	class Program
	{
		const string CMD_LINE_SWITCH_SPECIFY_DOMAIN = "Domain";

		private const int MAX_DAYS = 35;
		static private Type _domainTrustTypeInfo = typeof(DomainTrust);
		static private PropertyInfo[] _domainTrustTypeProperties = null;
		static private string _targetDomain = string.Empty;

		static void Main(string[] args)
		{
			//AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

			Console.WriteLine("Forest Trust collector.  From http://www.codeplex.com/ActiveDirectoryUtils.");
			Console.WriteLine("Version:  {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);

			// if (!((Environment.Version.Major >= 2) && (Environment.Version.Build >= 3053)))
			// we need at least .net 2.0 SP1. Higher is OK. 
			if ((Environment.Version.Major < 2) || ((Environment.Version.Major == 2) && (Environment.Version.Revision < 1433)))
			{
				Console.WriteLine(".NET 2.0 SP1 does not appear to be installed (detected " +
					Environment.Version.ToString() + ") .  Please goto http://www.microsoft.com/downloads and install .NET 2.0 SP1");
				return;
			}

			if (!parseCommandLineArgs(args))
			{
				return;
			}

			Domain d = null;

			if (!string.IsNullOrEmpty(_targetDomain))
			{
				try
				{
					d = Domain.GetDomain(_targetDomain);
				}
				catch (DirectoryServiceAccessException ex)
				{
					Console.WriteLine(ex.Message);
					return;
				}

			}
			else
			{
				try
				{
					d = Domain.GetCurrentDomain();
				}
				catch (LdapException ex)
				{
					Console.WriteLine(ex.Message);
					return;
				}
			}

			List<DomainTrust> trustedDomains = d.GetAllTrustRelationships();

			if ((trustedDomains == null) || (trustedDomains.Count == 0))
			{
				Console.WriteLine("No trusted domains found.");
				return;
			}
	
			StringBuilder sb = new StringBuilder();
			_domainTrustTypeProperties = _domainTrustTypeInfo.GetProperties();

			foreach (PropertyInfo pi in _domainTrustTypeProperties)
			{
				sb.AppendFormat("\"{0}\",", pi.Name);
			}
			sb.Remove(sb.Length - 1, 1);
			Console.WriteLine(sb.ToString());

			foreach (DomainTrust domTrust in trustedDomains)
			{
				outputTrustInformation(domTrust);
			}
		}

		static private void outputTrustInformation(DomainTrust trust)
		{
			StringBuilder sb = new StringBuilder();
			foreach (PropertyInfo pi in _domainTrustTypeProperties)
			{
				object o = pi.GetValue(trust, null);
				sb.AppendFormat("\"{0}\",", o != null ? o.ToString() : string.Empty);
			}
			sb.Remove(sb.Length - 1, 1);
			Console.WriteLine(sb.ToString());
		}

		private static bool parseCommandLineArgs(string[] args)
		{
			if (args.Length > 0)
			{
				foreach (string arg in args)
				{
					if (arg.Contains("/"))
					{
						if ((arg.ToLower().Contains(CMD_LINE_SWITCH_SPECIFY_DOMAIN.ToLower())) && (arg.Contains(":")))
						{
							string[] splitArg = arg.ToLower().Split(':');
							if (splitArg.Length == 2)
							{
								_targetDomain = splitArg[1];
							}
							else
							{
								return false;
							}
						}
						else if (arg.Contains("?"))
						{
							return outputHelp(string.Empty);
						}
						else
						{
							//We didn't find the switched typed.  Error out and return the help menu
							return outputHelp(arg);
						}
					}
					else    //Not a valid switch
					{
						return outputHelp(arg);
					}
				}
			}

			//Since we made it all the way through output all the commandline switches used
			foreach (string arg in args)
			{
				Console.WriteLine("Command Line Switch:  {0}", arg);
			}
			Console.WriteLine();
			return true;
		}

		private static bool outputHelp(string incorrectSyntax)
		{
			Console.WriteLine();
			if (!string.IsNullOrEmpty(incorrectSyntax))
			{
				Console.WriteLine("Incorrect Syntax:  {0}", incorrectSyntax);
				Console.WriteLine();
			}
			Console.WriteLine("Command Line Options:  {0} [/{1}:domain.com]", System.Reflection.Assembly.GetExecutingAssembly().GetName().Name, CMD_LINE_SWITCH_SPECIFY_DOMAIN);
			Console.WriteLine();
			Console.WriteLine("/{0} -Query specified domain for the list of trusts.", CMD_LINE_SWITCH_SPECIFY_DOMAIN);
			Console.WriteLine();
			Console.WriteLine("Example syntax:");
			Console.WriteLine("{0} /{1}:{2}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Name, CMD_LINE_SWITCH_SPECIFY_DOMAIN, "contoso");
			Console.WriteLine(" - Collect the trusts from the contoso domain.");
			return false;
		}

		private static void outputHeader()
		{
			Console.WriteLine("Trust Reporting Tool.  From http://www.codeplex.com/ActiveDirectoryUtils");
			Console.WriteLine("Version:  {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);
		}

		private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
		{
			Console.Clear();
			Console.WriteLine("This has experienced a critical error.  Please submit the below information to:\n http://www.codeplex.com/ActiveDirectoryUtils.");
			Console.WriteLine();
			outputHeader();
			Console.WriteLine(".NET Version: {0}", Environment.Version.ToString());
			Exception err = (Exception)e.ExceptionObject;
			Console.WriteLine("Type of Exception:\t{0}", err.GetType());
			Console.WriteLine("Error Message:\t{0}", err.Message);
			//Console.WriteLine("Stack Trace:\n{0}", err.StackTrace);
		}
	}
}
